PaperVison3Dでマウスドラッグしたい
- 2009 年 8月 18 日
PaperVision3Dでオブジェクトをマウスでドラッグさせたいだけなんだけど、これがよくわからん。
PV3Dで作られたコンテンツを見ていても意外にドラッグで操作させるものは少ない気もする。
僕の3D周りの知識が浅過ぎるせいなんだろうが、操作する感覚と一致させる3D空間のインターフェースってスゴく難しいと思うんだけどどうなんでしょうね。
3D、やっぱり知っとかなきゃならんって大前提のスキルがある。
それは座標空間と座標変換。
3D座標変換 – ゲームプログラミングWiki
そう3D空間にあるオブジェクトがやんなる位、度重なる座標変換を重ねて2Dに表示されている。
このあたりをまずしっかり理解しないとなぁと思った。
先のリンクにも初心者を消してきたって書いてあるしなぁ(w。時間かけてがんばろう。
さらにこの処理をするメソッドが最近のPVには充分備わっているようなんだが、その挙動一つ一つがイマイチ頭に入ってこない。これもなんとかせねばね。
色々調べて無茶苦茶な方法になっているかと思いますが、今のところ自分なりにやってみたのがこれ。
サンプル:PaperVison3Dでマウスドラッグしたい(マウスホイールでカメラ移動ね)
package index{ import flash.events.Event; import flash.events.MouseEvent; import org.papervision3d.cameras.Camera3D; import org.papervision3d.core.geom.renderables.Vertex3D; import org.papervision3d.core.math.Plane3D; import org.papervision3d.core.math.Number3D; import org.papervision3d.core.utils.InteractiveUtils; import org.papervision3d.core.utils.Mouse3D; import org.papervision3d.events.InteractiveScene3DEvent; import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.shadematerials.GouraudMaterial; import org.papervision3d.materials.WireframeMaterial; import org.papervision3d.objects.primitives.Sphere; import org.papervision3d.objects.primitives.Plane; import org.papervision3d.render.QuadrantRenderEngine; import org.papervision3d.view.BasicView; public class World extends BasicView{ public function World(viewportWidth:Number=640, viewportHeight:Number=480, scaleToStage:Boolean=true, interactive:Boolean=false, cameraType:String="TARGET"){ super(viewportWidth, viewportHeight, scaleToStage, interactive, cameraType); //マウス3Dを有効 Mouse3D.enabled = true; //ライト this.light = new PointLight3D(); this.light.y= 1000; //XZ無限平面 this.plane3d = new Plane3D( new Number3D( 0, 1, 0 ), new Number3D( 0, 0, 0 ) ); //地面 this.plane = new Plane( new WireframeMaterial(0x0000ff,0.5), 10000,10000,10,10); this.plane.rotationX = 90; //球 this.sphere = new Sphere( new GouraudMaterial( this.light, 0xffffff, 0x00ff00, 200 ), 100, 20, 20 ); this.sphere.material.interactive = true; this.sphere.y = 100; //レンダラ this.renderer = new QuadrantRenderEngine(); //カメラ this.camera.z = -1500; this.camera.orbit( -45, _yaw ); this.scene.addChild( this.plane ); this.scene.addChild( this.sphere ); this.startRendering(); this.addEventListener( Event.ADDED_TO_STAGE, this.addedToStageHandler, false, 0, true ); } public var light:PointLight3D; public var plane3d:Plane3D; public var plane:Plane; public var sphere:Sphere; public var subNum:Number3D; public var _yaw:Number = 90; public function addedToStageHandler(e:Event):void{ this.sphere.addEventListener( InteractiveScene3DEvent.OBJECT_PRESS, this.objectPressHandler, false, 0, true ); this.stage.addEventListener( MouseEvent.MOUSE_UP, this.mouseUpHandler, false, 0, true ); this.stage.addEventListener( MouseEvent.MOUSE_WHEEL, this.mouseWheelHandler, false, 0, true ); } public function objectPressHandler(e:InteractiveScene3DEvent):void{ //マウスプレスした位置のワールド座標 var mouseNum:Number3D = viewport.interactiveSceneManager.mouse3D.position; //オブジェクト中心との差 subNum = Number3D.sub( mouseNum, e.displayObject3D.position ); //無限平面をオブジェクトのy座標に移動 plane3d.setNormalAndPoint( new Number3D( 0, 1, 0 ), new Number3D( 0, -mouseNum.y, 0 ) ); //マウス位置監視 this.addEventListener( Event.ENTER_FRAME, enterFrameHandler, false, 0, true ) } public function mouseUpHandler(e:MouseEvent):void{ //監視解除 this.removeEventListener( Event.ENTER_FRAME, enterFrameHandler ); } public function mouseWheelHandler(e:MouseEvent):void{ this.camera.orbit( -45, _yaw += e.delta ); } public function enterFrameHandler(e:Event):void{ //ビュー座標??? var viewNum:Number3D = this.camera.unproject( this.viewport.containerSprite.mouseX, this.viewport.containerSprite.mouseY ); //ワールド座標?前方投影面の座標??? var worldNum:Number3D = Number3D.add( viewNum, camera.position ); var cameraVertex3D:Vertex3D = new Vertex3D( camera.x, camera.y, camera.z ); var worlsVertex3D:Vertex3D = new Vertex3D( worldNum.x, worldNum.y, worldNum.z ); //カメラの座標と投影面の座標を通る直線が無限平面と交差する点??? var intersectPoint:Vertex3D = plane3d.getIntersectionLine( worlsVertex3D, cameraVertex3D ); //座標に変換 var n:Number3D = intersectPoint.getPosition(); n = Number3D.sub( n, subNum ); this.sphere.position = n; } } } |
3D空間上に平面を置いて、マウスの座標を変換してカメラとその座標を通る直線と平面の交点座標を取得するって感じ???
うーん、たとえばDisplayObject3Dを入れ子にしたらこのままじゃうまくいかないし。ボロがいっぱい。